﻿#include "pch.h"
#include "sbcs.h"
#if __GNUC__
#include <wctype.h>
#endif
#include "PatrickPowell_snprintf.h"

#if _MSC_VER
#pragma warning(push)
#pragma warning(disable:4706)
#endif

//////////////////////////////////////////////////////////////////////////
// 유니코드 문자열 처리 

// MSC v13.10 - ctype.h
#define _k_iswalpha(c)					((L'A'<=(c) && (c)<=L'Z') || (L'a'<=(c) && (c)<=L'z'))
#define _k_iswdigit(c)					(L'0'<=(c) && (c)<=L'9')
#define _k_towlower(c)					((((c)>=L'A') && ((c)<=L'Z')) ? ((c)-L'A'+L'a') : (c))
#define _k_towupper(c)					((((c)>=L'a') && ((c)<=L'z')) ? ((c)-L'a'+L'A') : (c))

//
static void _wcs_output(kpointer ptr, size_t *currlen, size_t maxlen, int c)
{
	kwchar* buffer = (kwchar*)ptr;
	if (*currlen < maxlen)
		buffer[(*currlen)] = (kwchar)c;
	(*currlen)++;
}

//
static void _wcs_output_closure(kpointer ptr, size_t currlen, size_t maxlen)
{
	kwchar* buffer = (kwchar*)ptr;
	if (currlen < maxlen - 1)
		buffer[currlen] = L'\0';
	else if (maxlen > 0)
		buffer[maxlen - 1] = L'\0';
}

//
static void _wcs_file(kpointer ptr, size_t* currlen, size_t maxlen, int c)
{
	FILE* fp = (FILE*)ptr;
	fputwc((kwchar)c, fp);
	(*currlen)++;
}

/** vsnprintf */
kint k_vsnwprintf(kwchar* out, ksize_t len, const kwchar* fmt, va_list va)
{
	ksize_t res;

	k_return_value_if_fail(fmt != NULL, -1);

	res = doprw(_wcs_output, _wcs_output_closure, out, len, fmt, va);

	if (len)
		len--;

	return out ? (kint)K_MIN(res, len) : (kint)res;
}

/** vaprintf */
kint k_vaswprintf(kwchar** out, const kwchar* fmt, va_list va)
{
	ksize_t len;

	k_return_value_if_fail(out != NULL, -2);
	k_return_value_if_fail(fmt != NULL, -1);

	len = doprw(_wcs_output, _wcs_output_closure, NULL, 0, fmt, va);
	if (len <= 0)
	{
		*out = NULL;
		return 0;
	}

	*out = k_new(len + 1, kwchar);
	len = k_vsnwprintf(*out, len + 1, fmt, va);

	return (kint)len;
}

/** vaprintf */
//
kwchar* k_vapswprintf(const kwchar* fmt, va_list va)
{
	ksize_t len;
	kwchar* ret;

	k_return_value_if_fail(fmt != NULL, NULL);

	len = doprw(_wcs_output, _wcs_output_closure, NULL, 0, fmt, va);
	if (len <= 0)
		return NULL;

	ret = k_new(len + 1, kwchar);
	k_vsnwprintf(ret, len + 1, fmt, va);

	return ret;
}

/** vfprintf */
kint k_vfwprintf(FILE* file, const kwchar* fmt, va_list va)
{
	// 32K까지 가능
	k_return_value_if_fail(fmt != NULL, -1);
	return (kint)doprw(_wcs_file, NULL, file, 1024 * 32, fmt, va);
}

/** vprintf */
kint k_vwprintf(const kwchar* fmt, va_list va)
{
	return k_vfwprintf(stdout, fmt, va);
}

/** snprintf */
kint k_snwprintf(kwchar* out, ksize_t len, const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vsnwprintf(out, len, fmt, va);
	va_end(va);

	return ret;
}

/** asprintf */
kint k_aswprintf(kwchar** out, const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vaswprintf(out, fmt, va);
	va_end(va);

	return ret;
}

/** asprintf */
//
kwchar* k_apswprintf(const kwchar* fmt, ...)
{
	va_list va;
	kwchar* ret;

	va_start(va, fmt);
	ret = k_vapswprintf(fmt, va);
	va_end(va);

	return ret;
}

/** fprintf */
kint k_fwprintf(FILE* file, const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vfwprintf(file, fmt, va);
	va_end(va);

	return ret;
}

/** printf */
kint k_wprintf(const kwchar* fmt, ...)
{
	va_list va;
	kint ret;

	va_start(va, fmt);
	ret = k_vwprintf(fmt, va);
	va_end(va);

	return ret;
}

/** 문자열 해시 */
ksize_t k_wcshash(const kwchar* p)
{
	const kwchar* sz = p;
	ksize_t h = *sz++;
	if (!h)
		return 0;
	else
	{
		kint c;
		for (c = 0; *sz && c < 256; sz++, c++)
			h = (h << 5) - h + *sz;
		h = (h << 5) - h + c;
		return h;
	}
}

/** 문자열 해시 (대소문자구별안함) */
ksize_t k_wcsihash(const kwchar* p)
{
	const kwchar* sz = p;
	ksize_t h = _k_towupper(*sz);
	if (!h)
		return 0;
	else
	{
		kint c;
		sz++;
		for (c = 0; *sz && c < 256; sz++, c++)
			h = (h << 5) - h + _k_towupper(*sz);
		h = (h << 5) - h + c;
		return h;
	}
}

/** wcslen */
ksize_t k_wcslen(const kwchar* p)
{
	const kwchar* org = p;
	while (*p++);
	return p - org - 1;
}

/** wcscpy */
kwchar* k_wcscpy(kwchar* dest, const kwchar* src)
{
	kwchar* org = dest;
	while ((*dest++ = *src++));
	return org;
}

/** wcspcpy */
kwchar* k_wcspcpy(kwchar* dest, const kwchar*  src)
{
	do (*dest++ = *src);
	while (*src++ != L'\0');
	return dest - 1;
}

/** wcsncpy */
kwchar* k_wcsncpy(kwchar* dest, const kwchar* src, ksize_t len)
{
	kwchar* org = dest;

	while (len && (*dest++ = *src++))
		--len;
	*dest = L'\0';

	if (len)
	{
		while (--len)
			*dest++ = L'\0';
	}

	return org;
}

/** wcscat */
kwchar* k_wcscat(kwchar* dest, const kwchar* src)
{
	kwchar* org = dest;
	while (*dest) ++dest;
	while ((*dest++ = *src++));
	return org;
}

/** wcsncat */
kwchar* k_wcsncat(kwchar* dest, ksize_t len, const kwchar* src)
{
	kwchar* org = dest;

	while (*dest++);
	--dest;

	while (len--)
	{
		if (!(*dest++ = *src++))
			return org;
	}

	*dest = L'\0';
	return org;
}

/** wcscat의 여러 문자열 버전 */
kwchar* k_wcsconcat(kwchar* dest, ...)
{
	va_list va;
	kwchar* c = dest;
	kwchar* s;

	while (*c++);
	--c;

	va_start(va, dest);
	s = va_arg(va, kwchar*);
	while (s)
	{
		c = k_wcspcpy(c, s);
		s = va_arg(va, kwchar*);
	}
	va_end(va);

	return dest;
}

/** wcsdup, 복사한 메모리는 k_free 함수로 제거해야 한다 */
kwchar* k_wcsdup(const kwchar* p)
{
	kwchar* d;
	ksize_t len;

	len = k_wcslen(p) + 1;

	d = k_new(len, kwchar);
	k_wcscpy(d, p);

	return d;
}

/** wcsdup에 길이를 설정 */
kwchar* k_wcsndup(const kwchar* p, ksize_t len)
{
	kwchar* d;
	d = k_new(len + 1, kwchar);
	k_wcsncpy(d, p, len);
	return d;
}

/** 여러 문자열의 strdup */
kwchar* k_wcsdupcat(const kwchar* p, ...)
{
	va_list va;
	kwchar* str;
	kwchar* s, *c;
	ksize_t size;

	size = k_wcslen(p) + 1;
	va_start(va, p);
	s = va_arg(va, kwchar*);
	while (s)
	{
		size += k_wcslen(s);
		s = va_arg(va, kwchar*);
	}
	va_end(va);

	str = k_new(size, kwchar);
	c = str;

	c = k_wcspcpy(c, p);
	va_start(va, p);
	s = va_arg(va, kwchar*);
	while (s)
	{
		c = k_wcspcpy(c, s);
		s = va_arg(va, kwchar*);
	}
	va_end(va);

	return str;
}

/** wcsrev */
kwchar* k_wcsrev(kwchar* p)
{
	kwchar* s = p;
	kwchar* l = p;
	kwchar ch;

	while (*s++);
	s -= 2;

	while (l < s)
	{
		ch = *l;
		*l++ = *s;
		*s-- = ch;
	}

	return p;
}

/** wcsupr */
kwchar* k_wcsupr(kwchar* p)
{
	kwchar* s = p;

	for (; *s; ++s)
	{
		if ((*s >= L'a') && (*s <= L'z'))
			*s += (kwchar)(L'A' - L'a');
	}

	return p;
}

/** wcslwr */
kwchar* k_wcslwr(kwchar* p)
{
	kwchar* s = p;

	for (; *s; ++s)
	{
		if ((*s >= L'A') && (*s <= L'Z'))
			*s += (kwchar)(L'a' - L'A');
	}

	return p;
}

/** wcschr */
kwchar* k_wcschr(const kwchar* p, kint ch)
{
	while (*p && *p != (kwchar)ch) p++;
	return (*p == (kwchar)ch) ? (kwchar*)p : NULL;
}

/** wcsrchr */
kwchar* k_wcsrchr(const kwchar* p, kint ch)
{
	kwchar* s = (kwchar*)p;
	while (*s++);
	while (--s != p && *s != (kwchar)ch);
	return (*s == (kwchar)ch) ? (kwchar*)s : NULL;
}

/** wcsstr */
kwchar* k_wcsstr(const kwchar* p, const kwchar* s)
{
	kwchar* cp = (kwchar*)p;
	kwchar* s1, *s2;

	if (!*s)
		return (kwchar*)p;

	while (*cp)
	{
		s1 = cp;
		s2 = (kwchar*)s;

		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

/** wcsistr */
kwchar* k_wcsistr(const kwchar* p, const kwchar* s)
{
	kwchar* cp = (kwchar*)p;
	kwchar* s1, *s2;

	if (!*s)
		return (kwchar*)p;

	while (*cp)
	{
		s1 = cp;
		s2 = (kwchar*)s;

		while (*s1 && *s2 && !(_k_towupper(*s1) - _k_towupper(*s2)))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

/** wcsrstr */
kwchar* k_wcsrstr(const kwchar* p, const kwchar* s)
{
	kwchar* cp;
	ksize_t pl, sl, i;

	if (!*s)
		return (kwchar*)p;

	pl = k_wcslen(p);
	sl = k_wcslen(s);

	if (pl < sl)
		return NULL;

	cp = (kwchar*)p + pl - sl;
	while (cp >= p)
	{
		for (i = 0; i < sl; i++)
		{
			if (cp[i] != s[i])
				goto pos_next;
		}

		return cp;

pos_next:
		p--;
	}

	return NULL;
}

/** wcsbrk */
kwchar* k_wcsbrk(const kwchar* p, const kwchar* c)
{
	kwchar* t;
	while (*p)
	{
		for (t = (kwchar*)c; *t; t++)
		{
			if (*t == *p)
			{
				return (kwchar*)p;
			}
		}
		p++;
	}
	return NULL;
}

/** wcsleft */
kwchar* k_wcsleft(kwchar* dest, const kwchar* src, ksize_t len)
{
	ksize_t size = k_wcslen(src);

	if (len > size)
		k_wcscpy(dest, src);
	else
	{
		k_wcsncpy(dest, src, len);
		*(dest + len) = L'\0';
	}

	return dest;
}

/** wcsright */
kwchar* k_wcsright(kwchar* dest, const kwchar* src, ksize_t len)
{
	ksize_t size = k_wcslen(src);

	if (len > size)
		k_wcscpy(dest, src);
	else
	{
		k_wcsncpy(dest, src + size - len, len);
		*(dest + len) = L'\0';
	}

	return dest;
}

/** wcsmid */
kwchar* k_wcsmid(kwchar* dest, const kwchar* src, ksize_t pos, ksize_t len)
{
	ksize_t size = k_wcslen(src);

	if (pos > size)
		*dest = L'\0';
	else
	{
		k_wcsncpy(dest, src + pos, len);
		*(dest + len) = L'\0';
	}

	return dest;
}

/** wcsltrim */
kwchar* k_wcsltrim(kwchar* dest)
{
	kwchar* s;
	for (s = dest; *s && iswspace(*s); s++);
	if (dest != s)
		memmove(dest, s, (k_wcslen(s) + 1)*sizeof(kwchar));
	return dest;
}

/** wcsrtrim */
kwchar* k_wcsrtrim(kwchar* dest)
{
	ksize_t len = k_wcslen(dest);
	while (len--)
	{
		if (!iswspace(dest[len]))
			break;
		dest[len] = L'\0';
	}
	return dest;
}

/** wcstrim */
kwchar* k_wcstrim(kwchar* dest)
{
	return k_wcsrtrim(k_wcsltrim(dest));
}

/** wcsrem */
kwchar* k_wcsrem(kwchar* p, const kwchar* rmlist)
{
	kwchar* p1 = p;
	kwchar* p2 = p;

	while (*p1)
	{
		const kwchar* ps = rmlist;
		kcham b = FALSE;

		while (*ps)
		{
			if (*p1 == *ps)
			{
				b = TRUE;
				break;
			}
			++ps;
		}

		if (!b)
		{
			*p2 = *p1;
			++p2;
		}

		++p1;
	}

	*p2 = L'\0';

	return p;
}

/** wcseqv */
kcham k_wcseqv(const kwchar* p1, const kwchar* p2)
{
	return (p1 == p2) ? TRUE : k_wcscmp(p1, p2) == 0;
}

/** wcsieqv */
kcham k_wcsieqv(const kwchar* p1, const kwchar* p2)
{
	return (p1 == p2) ? TRUE : k_wcsicmp(p1, p2) == 0;
}

/** wcscmp */
kint k_wcscmp(const kwchar* p1, const kwchar* p2)
{
	kint ret = 0;

	while (!(ret = (kint)(*p1 - *p2)) && *p2)
		++p1, ++p2;

	if (ret < 0)		ret = -1;
	else if (ret > 0)	ret = 1;

	return ret;
}

/** wcsncmp */
kint k_wcsncmp(const kwchar* p1, const kwchar* p2, ksize_t len)
{
	if (!len)
		return 0;

	while (--len && *p1 && *p1 == *p2)
		++p1, ++p2;

	return (kint)(*p1 - *p2);
}

/** wcsicmp */
kint k_wcsicmp(const kwchar* p1, const kwchar* p2)
{
	kwchar f, l;

	do
	{
		f = (kwchar)_k_towlower(*p1);
		l = (kwchar)_k_towlower(*p2);
		++p1;
		++p2;
	} while (f && (f == l));

	return (kint)(f - l);
}

/** wcsnicmp */
kint k_wcsnicmp(const kwchar* p1, const kwchar* p2, ksize_t len)
{
	kwchar f, l;

	while (len && *p1 && *p2)
	{
		--len;

		f = (kwchar)_k_towlower(*p1);
		l = (kwchar)_k_towlower(*p2);

		if (f != l) return (f - l);
		++p1;
		++p2;
	}

	return (len) ? (kint)(p1 - p2) : 0;
}

/**
 * 문자열에서 와일드 카드 찾기.
 * Written by Jack Handy - jakkhandy@hotmail.com
 * (http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing)
 */
kint k_wcswcmatch(const kwchar* wild, const kwchar* string)
{
	const kwchar *cp = NULL, *mp = NULL;

	while ((*string) && (*wild != L'*'))
	{
		if ((*wild != *string) && (*wild != L'?'))
			return 0;
		wild++;
		string++;
	}

	while (*string)
	{
		if (*wild == L'*')
		{
			if (!*++wild)
				return 1;
			mp = wild;
			cp = string + 1;
		}
		else if ((*wild == *string) || (*wild == L'?'))
		{
			wild++;
			string++;
		}
		else
		{
			wild = mp;
			string = cp++;
		}
	}

	while (*wild == L'*')
		wild++;

	return !*wild;
}

/**
 * 문자열에서 와일드 카드 찾기.
 * Written by Jack Handy - jakkhandy@hotmail.com
 * (http://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing)
 */
kint k_wcsiwcmatch(const kwchar* wild, const kwchar* string)
{
	const kwchar *cp = NULL, *mp = NULL;

	while ((*string) && (*wild != L'*'))
	{
		if ((_k_towupper(*wild) != _k_towupper(*string)) && (*wild != L'?'))
			return 0;
		wild++;
		string++;
	}

	while (*string)
	{
		if (*wild == L'*')
		{
			if (!*++wild)
				return 1;
			mp = wild;
			cp = string + 1;
		}
		else if ((_k_towupper(*wild) == _k_towupper(*string)) || (*wild == L'?'))
		{
			wild++;
			string++;
		}
		else
		{
			wild = mp;
			string = cp++;
		}
	}

	while (*wild == L'*')
		wild++;

	return !*wild;
}

/** wcsfind */
kint k_wcsfind(const kwchar* src, const kwchar* find, ksize_t index)
{
	const kwchar* p = src + index;
	const kwchar* s1, *s2;

	while (*p)
	{
		s1 = p;
		s2 = find;

		while (*s1 && *s2 && !(*s1 - *s2))
		{
			++s1;
			++s2;
		}

		if (!*s2)
			return (kint)(src + index - p);
	}

	return -1;
}

/** 문자열이 숫자로 구성되어 있는지 알려준다. 1=숫자, -1=실수, 0=숫자아님 */
kint k_wcsisnum(const kwchar* s)
{
	kint ret = 0;
	kint dot = 0;
	for (; *s; ++s)
	{
		if (*s == L'+' || *s == L'-')
			continue;
		else if (!_k_iswdigit(*s))
		{
			if (*s != L'.')
			{
				ret = 0;		// 숫자아님
				break;
			}
			else
			{
				if (dot > 0)
				{
					ret = 1;	// 정수
					break;
				}
				else
				{
					ret = -1;	// 실수
					++dot;
				}
			}
		}
	}
	return ret;
}

/** wcstoi */
kint k_wcstoi(const kwchar* p)
{
	kint value;
	kint ch;
	kint sign;

	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t') ++p;

	ch = (kint)*p++;
	sign = ch;

	if (ch == '-' || ch == '+')
		ch = (kint)*p++;

	value = 0;
	while ((ch = (ch >= (kint)L'0' && ch <= (kint)L'9') ? ch - (kint)L'0' : -1) != -1)
	{
		value = 10 * value + ch;
		ch = (kint)*p++;
	}

	return (sign == L'-') ? -value : value;
}

/** wcstol */
klong k_wcstol(const kwchar* p)
{
	klong value;
	kint ch;
	kint sign;

	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t') ++p;

	ch = (kint)*p++;
	sign = ch;

	if (ch == L'-' || ch == L'+')
		ch = (kint)*p++;

	value = 0;
	while ((ch = (ch >= (kint)L'0' && ch <= (kint)L'9') ? ch - (kint)L'0' : -1) != -1)
	{
		value = 10 * value + ch;
		ch = (kint)*p++;
	}

	return (sign == L'-') ? -value : value;
}

/** wcstof */
float k_wcstof(const kwchar* p, kwchar** sret)
{
	return (float)k_wcstod(p, sret);
}

/** wcstod */
double k_wcstod(const kwchar* p, kwchar** sret)
{
	// code from DJGPP, Copyright (C) 1996 DJ Delorie

	double r = 0.0;	// result
	double d;		// scale
	kint e = 0;		// exponent
	kint sign = 1;		// +- 1.0
	kint esign = 1;
	kint i;
	kint flags = 0;

	while ((*p == L' ') || (*p == L'\t'))
		++p;

	if (*p == L'+')
		++p;
	else if (*p == L'-')
	{
		sign = -1;
		++p;
	}

	while ((*p >= L'0') && (*p <= L'9'))
	{
		flags |= 1;
		r *= 10.0;
		r += *p - L'0';
		++p;
	}

	if (*p == L'.')
	{
		d = 0.1L;
		++p;
		while ((*p >= L'0') && (*p <= L'9'))
		{
			flags |= 2;
			r += d*(*p - L'0');
			++p;
			d *= 0.1L;
		}
	}

	if (flags == 0)
	{
		if (sret) *sret = (kwchar*)p;
		return 0;
	}

	if ((*p == L'e') || (*p == L'E'))
	{
		++p;
		if (*p == L'+')
			++p;
		else if (*p == L'-')
		{
			++p;
			esign = -1;
		}
		if ((*p<L'0') || (*p>L'9'))
		{
			if (sret) *sret = (kwchar*)p;
			return r;
		}

		while ((*p >= L'0') && (*p <= L'9'))
		{
			e *= 10;
			e += *p - L'0';
			++p;
		}
	}

	if (esign < 0)
		for (i = 1; i <= e; ++i)
			r *= 0.1L;
	else
		for (i = 1; i <= e; ++i)
			r *= 10.0;

	if (sret) *sret = (kwchar*)p;
	return r*sign;
}

/** 진수 처리가 가능한 wcstoi */
kuint k_wcstoi_base(const kwchar* p, kint base)
{
	kuint v;
	kint ch;

	if (base < 2 || base>32)
		return 0;

	v = 0;
	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t')
		++p;

	ch = k_getbtv((*p++) & 0xFF);
	while (ch < base)
	{
		v = v*base + ch;
		ch = k_getbtv((*p++) & 0xFF);
	}

	return v;
}

/** 진수 처리가 가능한 wcstol */
kulong k_wcstol_base(const kwchar* p, kint base)
{
	kulong v;
	kint ch;

	if (base < 2 || base>32)
		return 0;

	v = 0;
	while (*p == L' ' || *p == L'\n' || *p == L'\r' || *p == L'\t')
		++p;

	ch = k_getbtv((*p++) & 0xFF);
	while (ch < base)
	{
		v = v*base + ch;
		ch = k_getbtv((*p++) & 0xFF);
	}

	return v;
}

/** 다음 문자열을 불린 참으로 함 TRUE, YES, CHAM, ON, 1 */
kcham k_wcstob(const kwchar* p)
{
	return k_wcsieqv(p, L"1") || k_wcsieqv(p, L"TRUE") || k_wcsieqv(p, L"YES") || k_wcsieqv(p, L"CHAM") || k_wcsieqv(p, L"ON");
}

/** 빈칸으로 채우기 */
ksize_t k_wcsfll(kwchar* dest, ksize_t pos, ksize_t end, int ch)
{
	ksize_t i, cnt;
	if (pos >= end)
		return pos;
	cnt = end - pos;
	for (i = 0; i < cnt; i++)
		dest[pos + i] = (kwchar)ch;
	return pos + cnt;
}

/** 글자로 채우기 */
ksize_t k_wcsspace(kwchar* dest, ksize_t pos, ksize_t end)
{
	ksize_t i, cnt;
	if (pos >= end)
		return pos;
	cnt = end - pos;
	for (i = 0; i < cnt; i++)
		dest[pos + i] = L' ';
	return pos + cnt;
}

/** 한줄 씩 읽기 */
ksize_t k_wcsline(const kwchar* text, kwchar* line, ksize_t* readsize, kcham removespace)
{
	const kwchar* pos;
	kwchar* dst;
	ksize_t len;

	if (!text)
		return 0;

	pos = text;
	dst = line;
	for (len = 0;; ++dst, ++pos, ++len)
	{
		if (*pos == L'\n' || *pos == L'\0')
		{
			++pos;
			++len;
			break;
		}
		*dst = *pos;
	}
	*dst = L'\0';

	if (readsize)
		*readsize = len;

	pos = line;
	len = 0;
	if (removespace)
	{
		for (; *pos; ++pos)
		{
			if (*pos == L'\n' || *pos == L'\r' || *pos == L' ' || *pos == L'\t')
				continue;
			else
			{
				*line = *pos;
				++line;
				++len;
			}
		}
	}
	else
	{
		for (; *pos; ++pos)
		{
			if (*pos == L'\n' || *pos == L'\r')
				continue;
			else
			{
				*line = *pos;
				++line;
				++len;
			}
		}
	}
	*line = L'\0';

	return len;
}

/** wcstok */
kwchar* k_wcstok(kwchar* string, const kwchar* control, kwchar** context)
{
	kwchar* token;
	const kwchar* ctl;

	k_return_value_if_fail(context != NULL, NULL);
	k_return_value_if_fail(string != NULL || *context != NULL, NULL);
	k_return_value_if_fail(control != NULL, NULL);

	if (!string)
		string = *context;

	while (*string)
	{
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (!*ctl)
			break;
		string++;
	}

	token = string;

	while (*string)
	{
		for (ctl = control; *ctl && *ctl != *string; ctl++)
			;
		if (*ctl)
		{
			*string++ = L'\0';
			break;
		}
		string++;
	}

	*context = string;

	return token == string ? NULL : token;
}

/** _wsplitpath */
kcham k_wsplitpath(const kwchar* path, kwchar* drv, kint drv_len, kwchar* dir, kint dir_len, kwchar* filename, kint filename_len, kwchar* ext, kint ext_len)
{
	const kwchar* tmp;
	const kwchar* slash;
	const kwchar* dot;
	kcham drvset = FALSE;
	kint	len = 0;
	kint	n;

	if (drv && drv_len)
		drvset = TRUE;

	if (drvset)
	{
		n = 3 - 2;
		tmp = path;

		while (n > 0 && *tmp != 0)
		{
			--n;
			++tmp;
		}
		if (*tmp == L':')
		{
			k_wcsncpy(drv, path, 3 - 1);
			path = tmp + 1;
		}
		else
		{
			if (drv)
				*((kwchar*)drv) = L'\0';
		}
	}

	slash = NULL;
	dot = NULL;
	tmp = path;

	for (; *tmp != 0; ++tmp)
	{
		if (*tmp == L'/' || *tmp == L'\\')
			slash = tmp + 1;
		else if (*tmp == L'.')
			dot = tmp;
	}

	if (slash)
	{
		if (dir && dir_len)
		{
			len = (kint)(slash - (kwchar*)path);
			k_wcsncpy(dir, path, (dir_len > len) ? len : dir_len);
		}
		path = slash;
	}
	else
	{
		if (dir)
			*((kwchar*)dir) = L'\0';
	}

	if (dot && (dot >= (kwchar*)path))
	{
		if (filename && filename_len)
		{
			len = (kint)(dot - (kwchar*)path);
			k_wcsncpy(filename, path, (filename_len > len) ? len : filename_len);
		}

		if (ext && ext_len)
		{
			len = (kint)(tmp - dot);
			k_wcsncpy(ext, dot, (ext_len > len) ? len : ext_len);
		}
	}
	else
	{
		if (filename && filename_len)
		{
			len = (kint)(tmp - (kwchar*)path);
			k_wcsncpy(filename, path, (filename_len > len) ? len : filename_len);
		}

		if (ext)
			*((kwchar*)ext) = L'\0';
	}

	return TRUE;
}

/** _wdivpath */
kcham k_wdivpath(const kwchar* path, kwchar* dir, kint dir_len, kwchar* filename, kint filename_len)
{
	const kwchar* slash = NULL;
	const kwchar* tmp = path;
	kint len;

	for (; *tmp != 0; ++tmp)
	{
		if (*tmp == L'/' || *tmp == L'\\')
			slash = tmp + 1;
	}

	if (slash)
	{
		if (dir && dir_len)
		{
			len = (kint)(slash - (const kwchar*)path);
			k_wcsncpy(dir, path, (dir_len > len) ? len : dir_len);
		}
		path = slash;
	}
	else
	{
		if (dir)
			*((kwchar*)dir) = L'\0';
	}

	if (filename && filename_len)
	{
		len = (kint)(tmp - (const kwchar*)path);
		k_wcsncpy(filename, path, (filename_len > len) ? len : filename_len);
	}

	return TRUE;
}

// 라이센스 정보는 strnatcmp를 참조 

static kint _k_wcs_nat_cmp_right(kwchar const* a, kwchar const* b)
{
	kint bias = 0;

	for (;; a++, b++)
	{
		if (!_k_iswdigit(*a) && !_k_iswdigit(*b))
			return bias;
		else if (!_k_iswdigit(*a))
			return -1;
		else if (!_k_iswdigit(*b))
			return +1;
		else if (*a < *b)
		{
			if (!bias)
				bias = -1;
		}
		else if (*a > *b)
		{
			if (!bias)
				bias = +1;
		}
		else if (!*a && !*b)
			return bias;
	}

	//return 0;
}

static kint _k_wcs_nat_cmp_left(kwchar const* a, kwchar const* b)
{
	for (;; a++, b++)
	{
		if (!_k_iswdigit(*a) && !_k_iswdigit(*b))
			return 0;
		else if (!_k_iswdigit(*a))
			return -1;
		else if (!_k_iswdigit(*b))
			return +1;
		else if (*a < *b)
			return -1;
		else if (*a > *b)
			return +1;
	}

	//return 0;
}

static kint _k_wcs_nat_internal(kwchar const* a, kwchar const* b, kcham incase)
{
	kwchar ca, cb;
	kint ai, bi;
	kint frac, res;

	for (ai = bi = 0;;)
	{
		ca = a[ai];
		cb = b[bi];

		while (iswspace(ca))
			ca = a[++ai];

		while (iswspace(cb))
			cb = b[++bi];

		if (_k_iswdigit(ca) && _k_iswdigit(cb))
		{
			frac = (ca == L'0' || cb == L'0');

			if (frac)
			{
				res = _k_wcs_nat_cmp_left(a + ai, b + bi);
				if (res != 0)
					return res;
			}
			else
			{
				res = _k_wcs_nat_cmp_right(a + ai, b + bi);
				if (res != 0)
					return res;
			}
		}

		if (!ca && !cb)
			return 0;

		if (incase)
		{
			ca = _k_towupper(ca);
			cb = _k_towupper(cb);
		}

		if (ca < cb)
			return -1;
		else if (ca > cb)
			return +1;

		++ai;
		++bi;
	}
}

/**
 * strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
 * Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
 */
kint k_wcsnatcmp(const kwchar* left, const kwchar* right)
{
	return _k_wcs_nat_internal(left, right, FALSE);
}

/**
 * strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
 * Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
 */
kint k_wcsnatcasecmp(const kwchar* left, const kwchar* right)
{
	return _k_wcs_nat_internal(left, right, TRUE);
}

#if _MSC_VER
#pragma warning(pop)
#endif
